#pragma once

#include "../mq_comm/mq_helper.hpp"
#include "../mq_comm/mq_log.hpp"
#include "../mq_comm/mq_msg.pb.h"
#include <google/protobuf/map.h>

#include <iostream>
#include <unordered_map>
#include <mutex>
#include <vector>
#include <string>
#include <memory>
namespace mq
{
    using namespace ns_helper;
    // 1.定义交换机
    struct Exchange
    {
        using ptr = std::shared_ptr<Exchange>;
        // 1.交换机名字
        std::string name;
        // 2.交换机类型
        ExchangeType type;
        // 3.持久化标志
        bool durable;
        // 4.是否自动删除
        bool auto_delete;
        // 5.其他字段
        google::protobuf::Map<std::string, std::string> args;

        Exchange()
        {
        }
        Exchange(const std::string &ename,
                 ExchangeType etype,
                 bool edurable,
                 bool eauto_delete,
                 const google::protobuf::Map<std::string, std::string> &eargs) : name(ename), type(etype), durable(edurable),
                                                                                 auto_delete(eauto_delete),
                                                                                 args(eargs)
        {
        }
        // args存储键值对，在存储数据库的时候，会组织⼀个格式字符串进⾏存储key=val&key=val...
        void setArgs(const std::string str_args) // 将字符串风格的args转换填充到args中
        {
            std::vector<std::string> sub_args;
            SplitHelper::split(str_args, "&", sub_args);

            for (auto &str : sub_args)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                args[key] = val;
            }
        }
        std::string getArgs() // 将args中的数据序列化为一个字符串, 并返回
        {
            std::string res;
            for (auto &pair : args)
            {
                res += pair.first + "=" + pair.second + "&";
            }
            return res;
        }
    };

    // 2.交换机持久化管理类
    // 存储到SQLite数据库中
    using ExchangMap = std::unordered_map<std::string, Exchange::ptr>;
    class ExchangeMapper
    {
    public:
        ExchangeMapper(const std::string &dbfile) : _sql_helper(dbfile)
        {
            std::string path = FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(path);

            assert(_sql_helper.open()); // 数据库打开不成功直接终止程序
            CreateTable();
        }
        void CreateTable()
        {
            std::string cre_sql = "create table if not exists exchange_table";
            cre_sql += "(name varchar(32) primary key, type int, durable int, auto_delete int, args varchar(255));";
            bool ret = _sql_helper.exec(cre_sql, nullptr, nullptr);
            if (!ret)
            {
                LOG(ERROR) << "创建交换机数据表失败 ! ! !\n";
                abort(); // 直接异常退出程序
            }
        }
        void RemoveTable()
        {
            std::string rem_sql = "drop table if exists exchange_table;";
            bool ret = _sql_helper.exec(rem_sql, nullptr, nullptr);
            if (!ret)
            {
                LOG(ERROR) << "交换机数据表删除失败 ! ! !\n";
                abort(); // 直接异常退出程序
            }
        }

        bool insert(Exchange::ptr &exp) // 将交换机属性持久化到SQLite数据库
        {
            std::stringstream ss;
            ss << "insert into exchange_table values(";
            ss << "'" << exp->name << "', ";
            ss << exp->type << ", ";
            ss << exp->durable << ", ";
            ss << exp->auto_delete << ", ";
            ss << "'" << exp->getArgs() << "');";
            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        void Remove(const std::string &name) // 移除交换机
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
        ExchangeMap Recovery() // 返回一个unordered_map, 与交换机内存管理类中对应
        {
            std::unordered_map<std::string, Exchange::ptr> res;
            std::string sql = "select * from exchange_table;";
            _sql_helper.exec(sql, selectCallback, &res);
            return res;
        }

    private:
        // col列
        // row
        // 调用多次, 每行调用一次
        static int selectCallback(void *arg, int col, char **row, char **fields)
        {
            ExchangeMap *result = (ExchangeMap *)arg;
            auto exp = std::make_shared<Exchange>();
            exp->name = row[0];
            exp->type = (mq::ExchangeType)std::stoi(row[1]);
            exp->durable = (bool)std::stoi(row[2]);
            exp->auto_delete = (bool)std::stoi(row[3]);
            if (row[4])
                exp->setArgs(row[4]);
            result->insert(std::make_pair(exp->name, exp));
            return 0; // 不能少(表示正常退出)
        }

    private:
        SqliteHelper _sql_helper;
    };
    // 3.交换机内存管理类(对外)
    class ExchangeManager
    {
    public:
        using ptr = std::shared_ptr<ExchangeManager>;

        ExchangeManager(const std::string dbfile) : _mapper(dbfile)
        {
            _exchanges = _mapper.Recovery();
        }

        bool declareExchange(const std::string &name,
                             ExchangeType type,
                             bool durable,
                             bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        // 声明交换机: 如果交换机存在就ok, 不能存在就创建
        {
            std::unique_lock<std::mutex> lock(_mtx); // 加锁保护
            auto it = _exchanges.find(name);         // 注意这个查找要在锁内
            if (it != _exchanges.end())
            {
                // 交换机存在直接返回
                return true;
            }
            auto exp = std::make_shared<Exchange>(name, type, durable, auto_delete, args);
            if (durable == true)
            {
                // 加入到数据库中
                bool ret = _mapper.insert(exp);
                if (ret == false)
                    return false;
            }
            _exchanges.insert(std::make_pair(name, exp));
            return true;
        }
        void deleteExchange(const std::string &name) // 删除交换机
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end())
            {
                return;
            }
            if (it->second->durable == true)
            {
                _mapper.Remove(name);
            }
            _exchanges.erase(name);
        }
        // 获取指定交换机对象
        Exchange::ptr selectExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end())
            {
                return Exchange::ptr();
            }
            return it->second;
        }
        bool IsExists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end())
            {
                return false;
            }
            return true;
        }

        size_t Size()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _exchanges.size();
        }
        // 清除所有交换机数据
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _mapper.RemoveTable();
            _exchanges.clear();
        }

    private:
        std::mutex _mtx;        // ExchangeManger类可能在多线程中使用, 需要加锁进行保护
        ExchangeMapper _mapper; // 持久化管理
        ExchangMap _exchanges;  // 交换机名称与交换机的映射(通过名字即可找到交换机)
    };
}